package data_operater

import (
	"fmt"
	"reflect"
	"strconv"
)

// ===== 数据获取器

type GetterType string

const (
	GetterTypeProp  GetterType = "prop"
	GetterTypeArray GetterType = "array"
	GetterTypeMerge GetterType = "merge"
)

type Getter interface {
	Get(data interface{}) (interface{}, error)
	SetNext(next Getter)
	GetFieldName() string
	GetType() GetterType
}

func NewPropGetter(fieldName string) Getter {
	return &PropGetter{
		fieldName: fieldName,
	}
}

type PropGetter struct {
	fieldName string
	next      Getter
}

func (p *PropGetter) GetType() GetterType {
	return GetterTypeProp
}

func (p *PropGetter) GetFieldName() string {
	return p.fieldName
}

func (p *PropGetter) SetNext(next Getter) {
	p.next = next
}

func (p *PropGetter) Get(data interface{}) (interface{}, error) {
	processedData, err := p.getData(data, p.fieldName)
	if err != nil {
		return nil, err
	}
	if p.next != nil {
		return p.next.Get(processedData)
	}
	return p.getData(data, p.fieldName)

}

func (p *PropGetter) getData(data interface{}, name string) (interface{}, error) {
	vData := reflect.ValueOf(data)
	if vData.Kind() == reflect.Ptr {
		vData = vData.Elem()
	}
	switch vData.Kind() {
	case reflect.Struct:
		return vData.FieldByName(name).Interface(), nil

	case reflect.Map:
		v := vData.MapIndex(reflect.ValueOf(name))
		if !v.IsValid() {
			return nil, fmt.Errorf("数据不存在指定key: %s", name)
		}
		return v.Interface(), nil
	default:
		return nil, fmt.Errorf("数据结构不是struct或是map")
	}
}

// NewArrayGetter 数组获取数据解释器
func NewArrayGetter(index string, child Getter) (Getter, error) {
	if index != "" {
		if numIndex, err := strconv.Atoi(index); err == nil {
			return &ArrayGetter{index: numIndex, child: child}, nil
		} else {
			return nil, fmt.Errorf("数组下标参数错误：%s", index)
		}
	}
	return &ArrayGetter{index: -1, child: child}, nil
}

type ArrayGetter struct {
	index int
	next  Getter
	child Getter
}

func (a *ArrayGetter) GetType() GetterType {
	return GetterTypeArray
}

func (a *ArrayGetter) GetFieldName() string {
	return a.child.GetFieldName()
}

func (a *ArrayGetter) SetNext(next Getter) {
	a.next = next
}

func (a *ArrayGetter) Get(data interface{}) (interface{}, error) {
	var processedData interface{}
	if a.child != nil {
		childData, err := a.child.Get(data)
		if err != nil {
			return nil, err
		}
		processedData = childData
	}
	tData := reflect.TypeOf(processedData)
	if tData.Kind() != reflect.Slice && tData.Kind() != reflect.Array {
		return nil, fmt.Errorf("当前数据不是数组或是切片格式")
	}
	if a.index >= 0 {
		if a.next != nil {
			rowData := a.getData(processedData, a.index)
			return a.next.Get(rowData)
		}
		return a.getData(processedData, a.index), nil
	} else {
		vData := reflect.ValueOf(processedData)
		// 数组模式
		result := make([]interface{}, 0)
		for i := 0; i < vData.Len(); i++ {
			// 获取子处理的值，或是数组原生的值
			rowData := a.getData(processedData, i)
			if a.next != nil {
				if nextData, err := a.next.Get(rowData); err != nil {
					return nil, err
				} else {
					result = append(result, nextData)
				}
			} else {
				result = append(result, rowData)
			}

		}
		return result, nil
	}
}

func (a *ArrayGetter) getData(data interface{}, index int) interface{} {
	vData := reflect.ValueOf(data)
	return vData.Index(index).Interface()

}

// ========= merge

type MergeExt interface {
	AddGetter(getter Getter)
	WrapLastGetter(func(getter Getter) Getter)
}

func NewMergeGetter() Getter {
	return &MergeGetter{children: make([]Getter, 0)}
}

type MergeGetter struct {
	children []Getter
}

func (m *MergeGetter) WrapLastGetter(f func(getter Getter) Getter) {
	childrenLen := len(m.children)
	if childrenLen >= 0 {
		lastGetter := m.children[childrenLen-1]
		m.children[childrenLen-1] = f(lastGetter)
	}
}

func (m *MergeGetter) GetType() GetterType {
	return GetterTypeMerge
}

func (m *MergeGetter) GetFieldName() string {
	// 容器节点，没有fieldName
	return ""
}

func (m *MergeGetter) AddGetter(getter Getter) {
	m.children = append(m.children, getter)
}

func (m *MergeGetter) Get(data interface{}) (interface{}, error) {
	result := make(map[string]interface{})
	for _, getter := range m.children {
		if childData, err := getter.Get(data); err == nil {
			result[getter.GetFieldName()] = childData
		}
	}
	return result, nil
}

func (m *MergeGetter) SetNext(next Getter) {
	panic("MergeGetter仅支持在最末尾的属性使用")
}
